import PySimpleGUI as sg
import configparser
import json
import time
import re
import threading
import hmac
import chardet
from zxtouch.zxtouch import zxtouch
from zxtouch.touchtypes import *

TOUCH_UP = 0
TOUCH_DOWN = 1
TOUCH_MOVE = 2
SET_SCREEN_SIZE = 9
keyset = [[250, 1800], [250, 1600], [250, 1400], [250, 1200], [250, 1000], [450, 1800], [450, 1600], [450, 1400], [450, 1200], [450, 1000], [650, 1800], [650, 1600], [650, 1400], [650, 1200], [650, 1000]]


Version = 'V1.6'

def formatSocketData(type, index, x, y):
    return '{}{:02d}{:05d}{:05d}'.format(type, index, int(x*10), int(y*10))

def click(down,up,suminonebit,timesub,device):
    device.s.send(("10" + str(suminonebit) + down).encode())
    time.sleep(0.5*timesub)
    device.s.send(("10" + str(suminonebit) + up).encode())

def findsite(fit):
    num = int(fit[1])
    return [int(keyset[num][0]),int(keyset[num][1])]

def creatkeylist(keysetlist):

    keylistlayout = []
    keylistlayout += [sg.Column([[sg.Text("key"+str(i), size=(4, 1)), sg.Text("x:"), sg.Input(str(keysetlist[i-1][0]),key='keyx'+str(i),size=(10, 1)), sg.Text("y:"), sg.Input(str(keysetlist[i-1][1]),key='keyy'+str(i),size=(10, 1))]]) for i in range(1,6)],
    keylistlayout += [sg.Column([[sg.Text("key"+str(i), size=(4, 1)), sg.Text("x:"), sg.Input(str(keysetlist[i-1][0]),key='keyx'+str(i),size=(10, 1)), sg.Text("y:"), sg.Input(str(keysetlist[i-1][1]),key='keyy'+str(i),size=(10, 1))]]) for i in range(6,11)],
    keylistlayout += [sg.Column([[sg.Text("key"+str(i), size=(4, 1)), sg.Text("x:"), sg.Input(str(keysetlist[i-1][0]),key='keyx'+str(i),size=(10, 1)), sg.Text("y:"), sg.Input(str(keysetlist[i-1][1]),key='keyy'+str(i),size=(10, 1))]]) for i in range(11,16)],

    keylistlayout += [[sg.Button("确定"),sg.Button("取消")]]
    return  keylistlayout
def blessyou(cpu):
    sec = b'ssysb0'
    h=hmac.new(sec,cpu.encode(),digestmod='MD5')
    print(h.hexdigest())
    return h.hexdigest()

def createbindip(ipstr):
    bindiplayout = [
        [sg.Text("IP:"),sg.Input(ipstr,key="ip",size=(30,1))],
        [sg.Button("确定"), sg.Button("取消")]
    ]
    return  bindiplayout

class Job(threading.Thread):

    def __init__(self,fmdatalist,bar,device):
        threading.Thread.__init__(self)
        self.__flag = threading.Event()     # 用于暂停线程的标识
        self.__flag.set()       # 设置为True
        self.__running = threading.Event()      # 用于停止线程的标识
        self.__running.set()      # 将running设置为True
        self.fmdatalist = fmdatalist
        self.bar = bar
        self.device = device
        self.isend = False

    def run(self):
        i=1
        for play in fmdatalist:
            self.__flag.wait()
            if not self.__running.isSet():
                break
            click(play['down'], play['up'], play['suminonebit'],play['timesub'],self.device)
            self.bar.UpdateBar(int(1000.0 * i / len(fmdatalist)))
            i+=1
            time.sleep(0.5*play['timesub'])
        self.isend = True

    def pause(self):
        self.__flag.clear()     # 设置为False, 让线程阻塞

    def resume(self):
        self.__flag.set()    # 设置为True, 让线程停止阻塞

    def stop(self):
        self.isend = False
        self.__flag.set()       # 将线程从暂停状态恢复, 如何已经暂停的话
        self.__running.clear()        # 设置为False

    def get_res(self):
        return self.isend
# 让所有文本居中

sg.SetOptions(text_justification='left')

# 蓝图不需要放到循环中
layout = [
            [sg.Button("设置键位坐标"),sg.Button("绑定设备IP")],
            [sg.Text('选择乐谱：'), sg.In(r'C:/Users/admin/AppData/LocalLow/Maple/Sky Studio/Sheet/Canon.C.txt',size=(40,1), key='music',focus=True), sg.FileBrowse('浏览'),sg.Button("确定")],
            [sg.Text("可以在演奏的同时选择下一首，当前演奏结束切换下一首")],
            [sg.Text("当前演奏："),sg.Text(key='name',size=(40,1))],
            [sg.Text("下一首："),sg.Text(key='nextname',size=(40,1))],
            [sg.Text("进度：   ") ,sg.ProgressBar(1000, orientation='h', size=(40, 7), key='progressbar')],
            [sg.Button("开始",disabled=True),sg.Button("暂停",disabled=True),sg.Button("继续",disabled=True),sg.Button("结束",disabled=True)],
        ]


win2_active = False
win3_active = False
nameflag = False
connectflag = False


# 视窗也只需要创建一次，不要放到循环里
window = sg.Window("光遇弹琴" + Version, layout)
bar = window["progressbar"]
test = window['name']
i=0
cf = configparser.ConfigParser()
cf.read("./test.conf")
secs = cf.sections()
if len(secs) == 0:
    cf.add_section('conf')
    cf.set('conf','key','')
    cf.set('conf', 'ip', '')
    cf.set('conf','keysetlist',str(keyset))
    cf.write(open("test.conf", "w"))


ipstr = cf.get('conf','ip')
# s = socket.socket()
try:
    device = zxtouch(ipstr)
    # s.connect((ipstr, 6000))
    device.accurate_usleep(100000)
except:
    pass
else:
    device.show_alert_box('skyauto'+Version,'Hello!',-1)
    #s.send(("12skyauto" + Version +";;Hello!;;-1").encode())
    connectflag = True

while True:
  event, values = window.read(timeout=1000)

  if event is '确定':
      with open(values['music'], mode='rb') as load_f:
          strF = load_f.read()
          codetype = chardet.detect(strF)['encoding']
          load_dict = json.loads(strF.decode(chardet.detect(strF)['encoding']))
      findnamelist = values['music'].split('/')
      findnamelist = findnamelist[-1].split('.txt')
      datas = load_dict[0]
      tempname = findnamelist[0]
      if not nameflag:
          window['name'].update(tempname)
          window['nextname'].update(tempname)
          source = values['music']
          nextsource = source
          nameflag = True
          window['开始'].Update(disabled=not connectflag)
      else:
          window['nextname'].update(tempname)
          nextsource = values['music']

  if event is '开始':

      window['开始'].Update(disabled=True)
      window['暂停'].Update(disabled=False)
      window['继续'].Update(disabled=False)
      window['结束'].Update(disabled=False)
      with open(source, mode='rb') as load_f:
          strF = load_f.read()
          codetype = chardet.detect(strF)['encoding']
          load_dict = json.loads(strF.decode(chardet.detect(strF)['encoding']))
      findnamelist = source.split('/')
      findnamelist = findnamelist[-1].split('.txt')
      datas = load_dict[0]
      songbits = datas['songNotes']
      suminonebit = 0
      fit = re.findall(r'\d+', songbits[0]['key'])
      keysetliststr = cf.get('conf', 'keysetlist')
      keysetlist = json.loads(keysetliststr)
      keyset = keysetlist
      keycd = findsite(fit)
      suminonebit += 1
      fmdatalist = []
      flag = 1
      tempfmdata = [formatSocketData(TOUCH_DOWN, int(fit[1]), keycd[0], keycd[1]),
                    formatSocketData(TOUCH_UP, int(fit[1]), keycd[0], keycd[1])]
      for i in range(1, len(songbits)):
          fit = re.findall(r'\d+', songbits[i]['key'])
          keycd = findsite(fit)
          timesub = songbits[i]['time'] - songbits[i - 1]['time']
          if (timesub == 0):
              tempfmdata[0] += formatSocketData(TOUCH_DOWN, int(fit[1]), keycd[0], keycd[1])
              tempfmdata[1] += formatSocketData(TOUCH_UP, int(fit[1]), keycd[0], keycd[1])
              suminonebit += 1
          else:
              fmdatalist.append(
                  {'down': tempfmdata[0], 'up': tempfmdata[1], 'timesub': timesub / 1000.0, 'suminonebit': suminonebit})
              suminonebit = 1
              tempfmdata[0] = formatSocketData(TOUCH_DOWN, int(fit[1]), keycd[0], keycd[1])
              tempfmdata[1] = formatSocketData(TOUCH_UP, int(fit[1]), keycd[0], keycd[1])
      fmdatalist.append({'down': tempfmdata[0], 'up': tempfmdata[1], 'timesub': timesub / 1000.0, 'suminonebit': suminonebit})
      thread1 = Job(fmdatalist,bar,device)
      thread1.start()
  if event is '暂停':
      thread1.pause()
  if event is '继续':
      thread1.resume()
  if event is '结束':
        thread1.stop()
        window['结束'].Update(disabled=True)
        window['继续'].Update(disabled=True)
        window['暂停'].Update(disabled=True)
        window['开始'].Update(disabled=not connectflag)
        window['name'].update(tempname)
        source = nextsource
        bar.UpdateBar(0)
  try:
      getres = thread1.get_res()
  except:
      pass
  else:
      if getres is True:
          window['结束'].Update(disabled=True)
          window['继续'].Update(disabled=True)
          window['暂停'].Update(disabled=True)
          window['开始'].Update(disabled=not connectflag)
          window['name'].update(tempname)
          source = nextsource
          bar.UpdateBar(0)


  # 当点击 window 右上角的 X，event 是 None，此时应当退出循环
  if event is None:
    break
  if not win2_active and event is "设置键位坐标":
      win2_active = True
      keysetliststr = cf.get('conf', 'keysetlist')
      keysetlist = json.loads(keysetliststr)
      keyset = keysetlist
      keylistlayout = creatkeylist(keysetlist)
      win2 = sg.Window('设置键位坐标', keylistlayout)

  if win2_active:
        ev2, vals2 = win2.read()
        print(ev2,vals2)
        win2_active = False
        if ev2 == '确定':
            for i in range(15):
                keysetlist[i][0] = int(vals2['keyx'+str(i+1)])
                keysetlist[i][1] = int(vals2['keyy'+str(i+1)])
            cf.set('conf', 'keysetlist', str(keysetlist))
            cf.write(open("test.conf", "w"))
            win2.close()
        if ev2 is None or ev2 == '取消':
            win2.close()
  if not win3_active and event is "绑定设备IP":
      win3_active = True
      ipstr = cf.get('conf','ip')
      bindiplayout = createbindip(ipstr)
      win3 = sg.Window('绑定设备IP', bindiplayout)
  if win3_active:
        ev3, vals3 = win3.read()
        print(ev3,vals3)
        win3_active = False
        if ev3 == '确定':
            ipstr = vals3['ip']
            try:
                device.disconnect()
                device = zxtouch(ipstr)
                time.sleep(0.1)  # 连接之后要休眠0.1秒
            except:
                connectflag = False
                window['开始'].Update(disabled=True)
                window['暂停'].Update(disabled=True)
                window['结束'].Update(disabled=True)
            else:
                device.show_alert_box('skyauto'+Version,'Hello!',-1)
                connectflag = True
                window['开始'].Update(disabled=not nameflag)
            cf.set('conf', 'ip', ipstr)
            cf.write(open("test.conf", "w"))
            win3.close()
        if ev3 is None or ev3 == '取消':
            win3.close()
  # 程序已经不会直接退出了，下一行就不需要了
  # window.read()
try:
    thread1.stop()
    device.disconnect()
except:
    pass
# 当退出循环的时候，就是程序退出之时，关掉 window
window.close()
exit(0)